package com.bizfx.component.views
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	
	import com.bizfx.collections.HashMap;
	import com.bizfx.component.controls.CommandBar;
	import com.bizfx.component.controls.IPager;
	import com.bizfx.component.controls.ISearcher;
	import com.bizfx.component.controls.Pager;
	import com.bizfx.component.controls.SearchBar;
	import com.bizfx.component.controls.SearchField;
	import com.bizfx.events.CommandRaiseEvent;
	import com.bizfx.events.CommonEvent;
	import com.bizfx.events.ListItemSelectorHeaderClickEvent;
	import com.bizfx.events.PagerEvents;
	import com.bizfx.events.SearcherEvents;
	import com.bizfx.events.ViewCommandEvent;
	import com.bizfx.utils.ListUtils;
	import com.bizfx.utils.StringUtils;
	
	import mx.collections.ArrayCollection;
	import mx.collections.IList;
	import mx.collections.Sort;
	import mx.collections.SortField;
	import mx.containers.Box;
	import mx.containers.VBox;
	import mx.controls.DataGrid;
	import mx.controls.dataGridClasses.DataGridColumn;
	import mx.core.UIComponent;
	import mx.effects.easing.Back;
	import mx.events.CollectionEvent;
	import mx.events.DataGridEvent;
	import mx.events.FlexEvent;
	import mx.events.ListEvent;
	
	[Style(name="commandsHorizontalAlign", type="String", enumeration="left,center,right", inherit="no", defaultValue="left")]
	
	[Style(name="commandsPosition", type="String", enumeration="top,bottom", inherit="no", defaultValue="top")]
	
	public class BaseListView extends BaseView implements IListView
	{
		protected var container:VBox;
		
		protected var searcherContainer:Box
		
		protected var commandBarContainer:Box;
		
		protected var listContainer:Box;
		
		protected var pagerContainer:Box;
		
		private var searcher:ISearcher;
		
		private var commandBar:CommandBar;
		
		public function BaseListView():void {
			super();
		}
		
		private var listDirty:Boolean = false;

		/**
		 * 列表对象
		 */
		protected var _list:DataGrid;
		[Bindable]
		public function get list():DataGrid {
			return this._list;
		}
		
		public function set list(value:DataGrid):void {
			if (this._list != value) {
				if (this._list) {
					_list.removeEventListener(ListEvent.ITEM_DOUBLE_CLICK, gridItemDBClickedHandler);
					_list.removeEventListener(ListEvent.ITEM_CLICK, gridItemClickedHandler);
					_list.removeEventListener(DataGridEvent.HEADER_RELEASE, gridHeadReleaseHandler);
				}
				_list = value;
				this.listDirty = true;
				this.invalidateDisplayList();
			}
		}
		
		private var searchFieldsDirty:Boolean = false;
		
		/**
		 * 搜索器
		 */
		private var _searchFields:IList;
		[Bindable("searchFieldsChanged")]
		public function get searchFields():IList {
			if (this._searchFields == null) {
				this._searchFields = new ArrayCollection();
			}
			return _searchFields;
		}
		
		public function set searchFields(value:IList):void {
			if (_searchFields != value) {
				_searchFields = value;
				this.searchFieldsDirty = true;
				this.invalidateDisplayList();
				this.dispatchEvent(new Event("searchFieldsChanged"));
			}
		}

		private var columnsDirty:Boolean = false;
		/**
		 * 列表列
		 */
		private var _columns:IList;
		[Bindable("columnsChanged")]
		public function get columns():IList {
			if (this._columns == null) {
				this._columns = new ArrayCollection();
				this._columns.addEventListener(CollectionEvent.COLLECTION_CHANGE, columnsChangeHandler);
			}
			return _columns;
		}
		
		public function set columns(value:IList):void {
			if (this._columns != value) {
				if (this._columns) {
					this._columns.removeEventListener(CollectionEvent.COLLECTION_CHANGE, columnsChangeHandler);
				}
				this._columns = value;
				this.columnsDirty = true;
				this.invalidateDisplayList();
				this.dispatchEvent(new Event("columnsChanged"));
			}
		}
		
		public function get searchConditions():IList
		{
			if (this.searcher)
				return this.searcher.searchConditions;
			else
				return new ArrayCollection();
		}
		
		/**
		 * 列表显示数目
		 */
		[Bindable]
		public function get pageSize():int
		{
			if (this.paging) {
				return this.pager.pageSize;
			} else {
				return 0;
			}
		}
		
		public function set pageSize(value:int):void
		{
			this.pager.pageSize = value;
		}
		
		public function get pageIndex():int
		{
			if (this.paging) {
				return this.pager.currentPageIndex;
			} else {
				return 0;
			}
		}

		[Bindable]
		public function get selectedItem():Object {
			return (this.list)?this.list.selectedItem:null;
		}
		
		public function set selectedItem(value:Object):void {
			if (this.list)
				this.list.selectedItem = value;
		}
		
		private var _selectedItems:IList;
		[Bindable]
		public function get selectedItems():IList {
			if (!_selectedItems) {
				_selectedItems = new ArrayCollection();
			}
			
			if (!this.allowMultipleSelection) {
				this._selectedItems.removeAll();
				if (this.list.selectedItem) {
					this._selectedItems.addItem(this.list.selectedItem);	
				}
			}
			return this._selectedItems;
		}
		
		public function set selectedItems(value:IList):void {
			this._selectedItems = value;
			if (!this.allowMultipleSelection) {
				if (value) {
					this.list.selectedItems = value.toArray();
				}
			}
		}
		
		private var _pager:IPager;
		[Bindable]
		public function get pager():IPager {
			if (!this._pager) {
				this._pager = new Pager();
				UIComponent(this._pager).percentWidth = 100;
				UIComponent(this._pager).height = 30;
				this.pager.paging = this.paging;
				this._pager.addEventListener(PagerEvents.PageSize_Change, listViewPageChangeChangedHandler);
				this._pager.addEventListener(PagerEvents.PageIndex_Change, listViewPageIndexChangedHandler);
				this.pagerContainer.addChild(this.pager as DisplayObject);
			}
			this._pager.paging = this.paging;
			return this._pager;
		}
		
		public function set pager(value:IPager):void {
			if (this._pager != value) {
				this._pager = value;
				if (this._pager) {
					this.pager.paging = this.paging;
					this._pager.addEventListener(PagerEvents.PageSize_Change, listViewPageChangeChangedHandler);
					this._pager.addEventListener(PagerEvents.PageIndex_Change, listViewPageIndexChangedHandler);
					this.pagerContainer.addChild(this.pager as DisplayObject);
				}
			}
		}
		
		private var _paging:Boolean = true;
		[Bindable]
		public function get paging():Boolean {
			return this._paging;
		}
		
		public function set paging(value:Boolean):void {
			if (_paging != value) {
				_paging = value;
			}
		}
		
		private var _searching:Boolean = true;
		[Bindable]
		public function get searching():Boolean {
			return this._searching;
		}
		
		public function set searching(value:Boolean):void {
			_searching = value;
		}
		
		private var _allowMultipleSelection:Boolean = false;
		[Bindable]
		public function get allowMultipleSelection():Boolean {
			return _allowMultipleSelection;
		}
		
		public function set allowMultipleSelection(value:Boolean):void {
			_allowMultipleSelection = value;
		}
		
		private var _itemDoubleClickCommand:String;
		[Bindable]
		public function get itemDoubleClickCommand():String {
			return _itemDoubleClickCommand;
		}
		
		public function set itemDoubleClickCommand(value:String):void {
			_itemDoubleClickCommand = value;
		}
		
		private var _idField:String = "id";
		[Bindable]
		public function get idField():String {
			return this._idField;
		}

		public function set idField(value:String):void {
			this._idField = value;
		}
		
		private var _sortField:SortField;
		[Bindable]
		public function get sortField():SortField {
			return this._sortField;
		}
		
		public function set sortField(value:SortField):void {
			this._sortField = value;
		}

		override protected function createChildren():void {
			super.createChildren();
			
			this.createContainers();
			
			this.createSearcher();
			
			this.createList();
			
			this.createPager();
			
			this.createCommandBar();
		}
		
		override protected function childrenCreated():void {
			if (this.getStyle("commandsHorizontalAlign") == undefined) {
				this.setStyle("commandsHorizontalAlign", "left");
			}
			
			if (this.getStyle("commandsPosition") == undefined) {
				this.setStyle("commandsPosition", "top");
			}
			super.childrenCreated();
		}
		
		protected function createContainers():void {
			if (!this.container) {
				this.container = new VBox()
				this.container.percentHeight = 100;
				this.container.percentWidth = 100;
				if (!this.contains(this.container)) {
					this.addChild(this.container);
				}	
			}
			
			if (!this.searcherContainer) {
				this.searcherContainer = new Box();
				this.searcherContainer.percentWidth = 100;
				if (!this.container.contains(this.searcherContainer)) {
					this.container.addChild(this.searcherContainer);
				}
			}
			
			if (!this.listContainer) {
				this.listContainer = new Box();
				this.listContainer.percentWidth = 100;
				this.listContainer.percentHeight = 100;
				if (!this.container.contains(this.listContainer)) {
					this.container.addChild(this.listContainer);
				}
			}
			
			if (!this.pagerContainer) {
				this.pagerContainer = new Box();
				this.pagerContainer.percentWidth = 100;
				if (!this.container.contains(this.pagerContainer)) {
					this.container.addChild(this.pagerContainer);
				}
			}
			
			if (!this.commandBarContainer) {
				this.commandBarContainer = new Box();
				this.commandBarContainer.percentWidth = 100;
				
				var commandsPositionStyle:String = this.getStyle("commandsPosition");
				var i:int = this.container.getChildIndex(this.searcherContainer) + 1;
				if (commandsPositionStyle == "bottom") {
					i = this.container.getChildren().length;
				}
				this.container.addChildAt(this.commandBarContainer, i);
			}
		}
		
		protected function createSearcher():void {
			if (!this.searcher) {
				//默认用SearchBar
				this.searcher = new SearchBar();
			}
			this.searcher.addEventListener(SearcherEvents.Searcher_DoSearch, searcherDoSearchHandler);
			UIComponent(this.searcher).percentWidth = 100;
			UIComponent(this.searcher).visible = this.searching;
			UIComponent(this.searcher).includeInLayout = this.searching;
			this.searcher.searchFields = this.searchFields;
			this.searcherContainer.addChild(DisplayObject(this.searcher));
		}
		
		protected function createList():void {
		}
		
		protected function createListColumns():void {
		}
		
		protected function createCommandBar():void {
			if (this.commandBarContainer && !this.commandBar) {
				this.commandBar = new CommandBar();
				this.commandBar.commands = this.commands;
				UIComponent(this.commandBar).percentWidth = 100;
				this.commandBarContainer.visible = this.commands.length > 0;
				this.commandBarContainer.includeInLayout = this.commands.length > 0;
				this.commandBar.addEventListener(CommandRaiseEvent.Command_Raise, commandBarCommandRaiseHandler);
				this.commandBarContainer.addChild(DisplayObject(this.commandBar));
			}
		}
		
		protected function createPager():void {
		}

		private var commandsHorizontalAlignDirty:Boolean = true;
		
		private var commandsPositionDirty:Boolean = false;
		
		override public function styleChanged(styleProp:String):void {
			super.styleChanged(styleProp);
			switch(styleProp) {  
				case "commandsHorizontalAlign":
					this.commandsHorizontalAlignDirty = true;
					this.invalidateDisplayList();
					break;
				case "commandsPosition":
					this.commandsPositionDirty = true;
					this.invalidateDisplayList();
					break;
			}
		}

		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			if (this.listDirty) {
				this.listDirty = false;
				if (this._list) {
					_list.doubleClickEnabled = true;
					_list.addEventListener(ListEvent.ITEM_DOUBLE_CLICK, gridItemDBClickedHandler);
					_list.addEventListener(ListEvent.ITEM_CLICK, gridItemClickedHandler);
					_list.addEventListener(DataGridEvent.HEADER_RELEASE, gridHeadReleaseHandler);
					this.listContainer.addChild(this._list);
				}
			}
			
			if (this.searchFieldsDirty) {
				this.searchFieldsDirty = false;
				if (this.searcher) {
					this.searcher.searchFields = this._searchFields;
				}
			}
			
			if (this.columnsDirty) {
				this.columnsDirty = false;
				if (this._columns) {
					this._columns.addEventListener(CollectionEvent.COLLECTION_CHANGE, columnsChangeHandler);
				}
			}
			
			if (this.commandsHorizontalAlignDirty) {
				this.commandsHorizontalAlignDirty = false;
				UIComponent(this.commandBar).setStyle("horizontalAlign", this.getStyle("commandsHorizontalAlign"));
			}
			
			if (this.commandsDirty) {
				this.commandsDirty = false;
				this.commandBar.commands = this.commands;
				this.commandBarContainer.visible = this.commands.length > 0;
				this.commandBarContainer.includeInLayout = this.commands.length > 0;
			}
			
			if (this.commandsPositionDirty) {
				this.commandsPositionDirty = false;
				var commandsPositionStyle:String = this.getStyle("commandsPosition");
				if (this.container.contains(this.commandBarContainer)) {
					this.container.removeChild(this.commandBarContainer);
				}
				var i:int = this.container.getChildIndex(this.searcherContainer) + 1;
				if (commandsPositionStyle == "bottom") {
					i = this.container.getChildren().length;
				}
				this.container.addChildAt(this.commandBarContainer, i);
			}
		}
		
		override public function bindViewDataToForm():void {
			if (this.viewDataSource != null && this.viewDataSource.hasOwnProperty("datas")) {
				this.list.dataProvider = this.viewDataSource.datas;
				
				if (this.allowMultipleSelection) {
					if (this.list.dataProvider is IList) {
						for each (var data:Object in this.list.dataProvider) {
							data["__selector"] = false;
						}
					}					
				}
				//清除已选项
				this.selectedItems.removeAll();
				this.selectedItem = null;
				if (this.pager != null) {
					this.pager.recordCount = this.viewDataSource.totalCount;
				}	
			} else {
				this.list.dataProvider = new ArrayCollection();
//				this.pager.recordCount = 0;
			}
		}
		
		public function hideAllViewCommands():void {
			this.commandBar.hideAllCommands();
		}
		
		public function showViewCommand(commandKey:String):void {
			this.commandBar.showCommandByKey(commandKey);
		}
		
		public function containListItem(item:Object):Boolean {
			var i:int = 0;
			if (this.list.dataProvider && this.list.dataProvider is IList) {
				var dataList:IList = this.list.dataProvider as IList;
				if (!StringUtils.isNullOrEmpty(this._idField)) {
					if (item.hasOwnProperty(this.idField)) {
						var itemId:String = item[this.idField];
						for (i = 0; i < dataList.length; i++) {
							var data:Object = dataList.getItemAt(i);
							if (data.hasOwnProperty(this.idField)){
								var id:String = data[this.idField].toString();
								if (itemId == id) {
									return true;
								}
							}
						}	
					}
				} 

				for (i = 0; i < dataList.length; i++) {
					if (item == dataList.getItemAt(i)) {
						return true;
					}
				}
			}
			return false;
		}
		
		override public function refresh():void {
			if (this.searcher) {
				this.searcher.reset();
			}
			super.refresh();
		}
		
		public function selectListItem(item:Object, selected:Boolean):void {
			if (item) {
				item["__selector"] = selected;
				if (selected) {
					this.selectedItems.addItem(item);
				} else {
					ListUtils.removeFromList(this.selectedItems, item);
				}	
			}
		}
		
		/**
		 * Event Handlers
		 */
		
		private function searcherDoSearchHandler(event:CommonEvent):void {
			this.dispatchEvent(new CommonEvent(event.type, event.data));
		}
		
		protected function gridItemDBClickedHandler(event:ListEvent):void {
			if (!StringUtils.isNullOrEmpty(this.itemDoubleClickCommand)) {
				var command:ViewCommand = this.getViewCommandByKey(this.itemDoubleClickCommand);
				if (command != null){
					var e:ViewCommandEvent = new ViewCommandEvent(ViewCommandEvent.ViewCommand_Raise, command);
					this.dispatchEvent(e);
				}
			}
		}
		
		protected function gridItemClickedHandler(event:ListEvent):void {
			var data:Object = (event.target as DataGrid).selectedItem;
			if (data) {
				var selected:Boolean = !(data["__selector"] as Boolean);
				this.selectListItem(data, selected);
			}
		}
		
		private function gridHeadReleaseHandler(event:DataGridEvent):void {
			var column:ListViewColumn = null;
			for each(var col:ListViewColumn in this.columns) {
				if (col.dataField == event.dataField) {
					column = col;
					break;
				}
			}
			
			if (!column || !column.serverSideSort) {
				return;
			}
			if (!this.sortField) {
				this.sortField =  new SortField(column.serverSideSortField, false, false);
			} else {
				if (this.sortField.name == column.serverSideSortField) { 
					this.sortField.descending = !this.sortField.descending;
				} else {
					this.sortField.name = column.serverSideSortField;
					this.sortField.descending = false;
				}
			}

			var e:CommonEvent = new CommonEvent("listSort", this.sortField);
			this.dispatchEvent(e);
		}
		
		private function commandBarCommandRaiseHandler(event:CommandRaiseEvent):void {
			var command:ViewCommand = event.viewCommand;
			var e:ViewCommandEvent = new ViewCommandEvent(ViewCommandEvent.ViewCommand_Raise, command);
			this.dispatchEvent(e);
		}
		
		protected function columnsChangeHandler(event:CollectionEvent):void {
			this.createList();
		}
		
		private function listViewPageIndexChangedHandler(event:CommonEvent):void {
			this.dispatchEvent(new CommonEvent(event.type, event.data));
		}
		
		private function listViewPageChangeChangedHandler(event:CommonEvent):void {
			this.dispatchEvent(new CommonEvent(event.type, event.data));
		}
		
		protected function selectorHeaderHandler(event:ListItemSelectorHeaderClickEvent):void {
			if (this.list.dataProvider is IList) {
				for each (var data:Object in this.list.dataProvider) {
					this.selectListItem(data, event.selected);
				}				
			}
		}
	}
}